//============================================================================
//  Module Name:
//    MLMETxRx.C
//
//  Description:
//    The interface between MDS (MAC Data Service) and MLME.
//
//  Revision History:
//  --------------------------------------------------------------------------
//          200209      UN20 Jennifer Xu
//                      Initial Release
//          20021108    PD43 Austin Liu
//          20030117    PD43 Austin Liu
//                      Deleted MLMEReturnPacket and MLMEProcThread()
//
//  Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved.
//============================================================================
#include "os_common.h"

void MLMEResetTxRx(IN PWB32_ADAPTER Adapter)
{
    INT     i;

    // Reset the interface between MDS and MLME
    for (i = 0; i < MAX_NUM_TX_MMPDU; i++)
        Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE;
    for (i = 0; i < MAX_NUM_RX_MMPDU; i++)
        Adapter->sMlmeFrame.SaveRxBufSlotInUse[i] = FALSE;
        
    Adapter->sMlmeFrame.wNumRxMMPDUInMLME   = 0;
    Adapter->sMlmeFrame.wNumRxMMPDUDiscarded = 0;
    Adapter->sMlmeFrame.wNumRxMMPDU          = 0;
    Adapter->sMlmeFrame.wNumTxMMPDUDiscarded = 0;
    Adapter->sMlmeFrame.wNumTxMMPDU          = 0;
    Adapter->sLocalPara.boCCAbusy    = FALSE;
    Adapter->sLocalPara.iPowerSaveMode     = PWR_ACTIVE;     // Power active
}

//=============================================================================
//	Function:
//    MLMEGetMMPDUBuffer()
//
//	Description:
//    Return the pointer to an available data buffer with
//    the size MAX_MMPDU_SIZE for a MMPDU.
//
//  Arguments:
//    Adapter   - pointer to the miniport adapter context.
//
//	Return value:
//    NULL     : No available data buffer available
//    Otherwise: Pointer to the data buffer
//=============================================================================
UCHAR *MLMEGetMMPDUBuffer(IN PWB32_ADAPTER Adapter)
{
    INT i;
    UCHAR *returnVal;
    
    for (i = 0; i< MAX_NUM_TX_MMPDU; i++)
    {
        if (Adapter->sMlmeFrame.TxMMPDUInUse[i] == FALSE)
            break;
    }
    if (i >= MAX_NUM_TX_MMPDU) return NULL;

    returnVal = (UCHAR *)&(Adapter->sMlmeFrame.TxMMPDU[i]);
	Adapter->sMlmeFrame.TxMMPDUInUse[i] = TRUE;

    return returnVal;
}

//=============================================================================
UCHAR MLMESendFrame( PWB32_ADAPTER Adapter,
				   UCHAR *pMMPDU,
				   USHORT len,
				   IN UCHAR DataType)
/*	DataType : FRAME_TYPE_802_11_MANAGEMENT, FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE,
				FRAME_TYPE_802_11_DATA */
{
	if( Adapter->sMlmeFrame.IsInUsed != PACKET_FREE_TO_USE )
	{
		Adapter->sMlmeFrame.wNumTxMMPDUDiscarded ++;
		return FALSE;
	}
	Adapter->sMlmeFrame.IsInUsed = PACKET_COME_FROM_MLME;

	// Keep information for sending
	Adapter->sMlmeFrame.pMMPDU = pMMPDU;
	Adapter->sMlmeFrame.DataType = DataType;
	Adapter->sMlmeFrame.len = len; // It must be the last setting due to QUERY_SIZE_SECOND of Mds
	Adapter->sMlmeFrame.wNumTxMMPDU++;

	// H/W will enter power save by set the register. S/W don't send null frame
	//with PWRMgt bit enbled to enter power save now.
	/*
	//PowerSaveMode bit of FRAME_TYPE_802_11_DATA frames have been set before 
	//this function, such as SendNullData()
	if (DataType != FRAME_TYPE_802_11_DATA)
	{
		if (Adapter->sLocalPara.iPowerSaveMode == PWR_SAVE)
		{
    	    // Enable the PWRMgt bit in the Frame Control field
        	pMMPDU[1] |= 0x10;
		}
    }
	*/

	// Transmit NDIS packet
	Mds_Tx( Adapter );
    #ifdef _PE_TX_DUMP_
    WBDEBUG(("MLMESendFrame->mds_tx_ok\n"));
    #endif
	//Suppose Tx is always successful even it is not sent in Mds_Tx(). -- WKChen
	//(1)If it is "probe request", we can't queue it in the Mds_Tx(). Because
	//	 the channel may have been changed
	//(2)If it is "authentication or association" frame, the connection will fail.
	// The follow function will be called in GET_DESCRIPTOR_SECOND_COMPLETED
	// It can make sure the buffer can be released safely.
	// MLME_SendComplete( Adapter, 0, TRUE); 20051220 Move to GET_DESCRIPTOR_SECOND_COMPLETED

	return TRUE;
}

VOID
MLME_GetNextPacket( IN PADAPTER Adapter, IN PDESCRIPTOR pDes )
{
	DESCRIPTOR_ADD_BUFFER( pDes, Adapter->sMlmeFrame.pMMPDU, Adapter->sMlmeFrame.len );
	DESCRIPTOR_SET_TYPE( pDes, Adapter->sMlmeFrame.DataType );
}

VOID MLMEfreeMMPDUBuffer(IN PWB32_ADAPTER Adapter, IN PCHAR pData)
{
	int i;

    // Reclaim the data buffer
    for (i = 0; i < MAX_NUM_TX_MMPDU; i++)
    {
        if (pData == (PCHAR)&(Adapter->sMlmeFrame.TxMMPDU[i]))
            break;
    }
    if (Adapter->sMlmeFrame.TxMMPDUInUse[i])
        Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE;
    else  {
        // Something wrong
        // PD43 Add debug code here???
    }

}

VOID
MLME_SendComplete( IN PADAPTER Adapter, IN UCHAR PacketID, IN BOOLEAN SendOK )
{
	MLME_TXCALLBACK		TxCallback;
	K_MSG				sMlmeMsg;
	UCHAR				DataTmp[200];

	OS_MEMORY_COPY( DataTmp, Adapter->sMlmeFrame.pMMPDU, Adapter->sMlmeFrame.len );
    #ifdef _PE_TX_DUMP_
	WBDEBUG(( "dump tx callback, len=%d\n", Adapter->sMlmeFrame.len ));
	DataDmp( Adapter->sMlmeFrame.pMMPDU, Adapter->sMlmeFrame.len, 0 );
    #endif

    // Reclaim the data buffer
	Adapter->sMlmeFrame.len = 0;
	MLMEfreeMMPDUBuffer( Adapter, Adapter->sMlmeFrame.pMMPDU );


	sMlmeMsg.wMsgType = MLMEMSG_TX_CALLBACK;
	//TxCallback.wFrameType = pData[0];  //&0xf0;
	//TODO : ?? The pData has been returned, but we still use it to know what kind
	//			of mlme frame it is. Will it be dangerous??
	//TxCallback.psFramePtr = pData;
	TxCallback.psFramePtr = DataTmp;
	if( SendOK )
		TxCallback.bResult = MLME_SUCCESS;
	else
		TxCallback.bResult = TRANSMIT_FRAME_FAIL;

	sMlmeMsg.pMsgPtr = &TxCallback;
	MLME_Entry(Adapter, &sMlmeMsg);

	// Return resource
	Adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE;
	#ifdef _PE_TX_DUMP_
	WBDEBUG(("!!Return MLME tx packet\n"));
	#endif
}

//===========================================================================
//	Function:
//		MLMERcvFrame()
//
//	Description:
//      To receive and ready to process the MLME frame, excluding the FCS
//      field.
//      MDS usually passes the MMPDU, which may be segmented and stored into
//      several Rx data buffers, to this function with a pointer to an array
//      of the RXBUFFER structure and the number of entries in the array.
//
//  Arguments:
//      Adapter         - Pointer to the Miniport Adatper Context.
//      pRxBufferArray  - Pointer to the first RXBUFFER for the Rx frame.
//      NumOfBuffer     - Number of the buffer segment.
//      ReturnSlotIndex - Reserved for Rx handler
//
//	Return value:
//      None.
//===========================================================================
void
MLMERcvFrame(
    IN PWB32_ADAPTER    Adapter,
    IN PRXBUFFER        pRxBufferArray,
    IN UCHAR             NumOfBuffer,
    IN UCHAR            SlotIndex)
{
    INT     i, FreeSlot, FrameSize;
	K_MSG	sMsg;
	RXDATA	sRxFrameData;
	#ifdef _IBSS_BEACON_SEQ_STICK_
	BOOLEAN	boIsProbeReq = FALSE;
	#endif

    if (pRxBufferArray == NULL || NumOfBuffer == 0)   {
        // Invalid parameters
        return;
    }

    if (Adapter->sMlmeFrame.wNumRxMMPDUInMLME >= MAX_NUM_RX_MMPDU ||
         pRxBufferArray->pBufferAddress == NULL)   {
        // Exceeding the number of MMPDUs allowed in the MLME module
        Adapter->sMlmeFrame.wNumRxMMPDUDiscarded ++;
        return;
    }

    Adapter->sMlmeFrame.wNumRxMMPDUInMLME ++;
    for (i = 0; i < MAX_NUM_RX_MMPDU; i++)   {
        // To find an free slot to store the info.
        if (Adapter->sMlmeFrame.SaveRxBufSlotInUse[i] == FALSE)
            break;
    }
    if (i >= MAX_NUM_RX_MMPDU) {
        // Should not occur.
        Adapter->sMlmeFrame.wNumRxMMPDUInMLME --;
        return;
    }
    FreeSlot = i;
    Adapter->sMlmeFrame.SaveRxBufSlotInUse[FreeSlot]      = TRUE;

    //=================================================
    // Collect the frame data in the buffer segments
    // into a single data buffer
    //=================================================
    FrameSize = 0;
    for (i = 0; i < (INT) NumOfBuffer; i++)
	{
        if (FrameSize + pRxBufferArray->BufferSize > MAX_MMPDU_SIZE    ||
             pRxBufferArray->pBufferAddress == NULL)
		{
            // Discard the management frame larger than MAX_MMPDU_SIZE
            // Should increase the current MAX_MMPDU_SIZE if exists such MMPDU
            //
            Adapter->sMlmeFrame.wNumRxMMPDUInMLME --;
            Adapter->sMlmeFrame.SaveRxBufSlotInUse[FreeSlot] = FALSE;
            Adapter->sMlmeFrame.wNumRxMMPDUDiscarded ++;
            return;
        }
        ///NdisMoveMemory(&Adapter->sMlmeFrame.RxMMPDU[FreeSlot][FrameSize],
        OS_MEMORY_COPY( &Adapter->sMlmeFrame.RxMMPDU[FreeSlot][FrameSize],
                        pRxBufferArray->pBufferAddress,
                        pRxBufferArray->BufferSize);
        FrameSize = FrameSize + pRxBufferArray->BufferSize;
        pRxBufferArray ++;                    // Pointer to next buffer segment
    }
	#ifdef _PE_RX_DUMP_
	//	WBDEBUG(("RX: Receive len in mlme =%d\n", FrameSize));
	#endif
    //======================
	// MLME data processing
    //======================
    Adapter->sMlmeFrame.wNumRxMMPDU ++;

	sRxFrameData.pbFramePtr = Adapter->sMlmeFrame.RxMMPDU[FreeSlot];
	sRxFrameData.FrameLength = FrameSize;
	sMsg.wInstance = SlotIndex;
	sMsg.pMsgPtr = &sRxFrameData;
	if ((sRxFrameData.pbFramePtr[0]&0xf0) == MAC_SUBTYPE_MNGMNT_BEACON)
	{
		sMsg.wMsgType = SCANMSG_BEACON;
		Scan_Entry(Adapter, &sMsg);
	}
	else if ((sRxFrameData.pbFramePtr[0]&0xf0) == MAC_SUBTYPE_MNGMNT_PROBE_RESPONSE)
	{
		sMsg.wMsgType = SCANMSG_PROBE_RESPONSE;
		Scan_Entry(Adapter, &sMsg);
	}
	//else if ((sRxFrameData.pbFramePtr[0]&0xf0) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) // ignore Probe_Req
	//{
	//	sMsg.wMsgType = MLMEMSG_RCV_MLMEFRAME;
	//	MLME_Entry(Adapter, &sMsg);
	//}
	else if ((sRxFrameData.pbFramePtr[0]&0xf0) == MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) // ignore Probe_Req
	{
		#ifdef _IBSS_BEACON_SEQ_STICK_
		boIsProbeReq = TRUE;
		#endif
	}
	else// if ((sRxFrameData.pbFramePtr[0]&0xf0) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) // ignore Probe_Req
	{
		sMsg.wMsgType = MLMEMSG_RCV_MLMEFRAME;
		MLME_Entry(Adapter, &sMsg);
	}

    // Note: NDIS driver does not support such function. Reclaim the received
    // packet resource to the MDS part immediately.
    Adapter->sMlmeFrame.wNumRxMMPDUInMLME --;
    Adapter->sMlmeFrame.SaveRxBufSlotInUse[FreeSlot] = FALSE;
	#ifdef _IBSS_BEACON_SEQ_STICK_
	if (boIsProbeReq)
	{
		if ((psSME->wDesiredJoinBSS != 0) &&
			//(Adapter->Mds.TxToggle == FALSE) &&
			(psBSS(psSME->wDesiredJoinBSS)->bBssType == IBSS_NET))
		{
			if ((psLOCAL->wConnectedSTAindex != 0) &&
				(Adapter->Mds.TxToggle == TRUE))
				return;
			//SendBCNullData(Adapter, psSME->wDesiredJoinBSS);
			//vMlmeTimerStart(Adapter, 1, 100);	//100ms, utilize the timer of psBSS(1)
			vMlmeTimerStart(Adapter, 1, 300);	//300ms, utilize the timer of psBSS(1)
		}
	}
	#endif
    return;
}
#ifdef _IBSS_BEACON_SEQ_STICK_
CHAR SendBCNullData(PWB32_ADAPTER Adapter, USHORT wIdx)
{

	PUCHAR	msg;
	struct Data_Frame* msgHeader;

	if ((msg=MLMEGetMMPDUBuffer(Adapter))==NULL)
	{
		Adapter->sMlmeFrame.wNumTxMMPDUDiscarded++;
		return -1;  // fail get free msg buffer
	}
	//wConnectIdx = psLOCAL->wConnectedSTAindex;
	msgHeader = (struct Data_Frame *) &msg[0];

	// setup Frame-Header subfields
	msgHeader->frame_control.mac_frame_info = MAC_SUBTYPE_DATA_NULL;
	if (psBSS(wIdx)->bBssType == ESS_NET)
	    msgHeader->frame_control.to_ds      = 1;
	else
	    msgHeader->frame_control.to_ds      = 0;
    msgHeader->frame_control.from_ds    = 0;
	msgHeader->frame_control.more_frag 	= 0;
    msgHeader->frame_control.retry      = 0;
	msgHeader->frame_control.more_data 	= 0;
    msgHeader->frame_control.order      = 0;
	//if (PowerMode  == PWR_SAVE)
	//    msgHeader->frame_control.pwr_mgt    = 1;
	//else
    	msgHeader->frame_control.pwr_mgt    = 0;
    msgHeader->frame_control.WEP        = 0;
    msgHeader->duration                 = 0;    // Set by the MDS
	
	//memcpy(msgHeader->Addr1, psBSS(Adapter->sLocalPara.wConnectedSTAindex)->abBssID,MAC_ADDR_LENGTH);
	OS_MEMORY_COPY( msgHeader->Addr1, "\xff\xff\xff\xff\xff\xff", MAC_ADDR_LENGTH );
	//memset(msgHeader->Addr1, 0x55, MAC_ADDR_LENGTH);
	OS_MEMORY_COPY( msgHeader->Addr2, Adapter->sLocalPara.ThisMacAddress, MAC_ADDR_LENGTH );
	OS_MEMORY_COPY( msgHeader->Addr3, psBSS(wIdx)->abBssID, MAC_ADDR_LENGTH );
	// FrameSequenceNumber is generated by HW-MAC

	OS_MEMORY_CLEAR( &msgHeader->Sequence_Control, MAC_ADDR_LENGTH );

    // now send this message out
	if (1 == MLMESendFrame( Adapter,
					(UCHAR *) &msg[0],
					//sizeof(struct Data_Frame) - 6,
					sizeof(struct Data_Frame),
					FRAME_TYPE_802_11_DATA))
        return 1;                           // Has sent to the Tx handler.
	else
	{
		//return MLME buffer
		MLMEfreeMMPDUBuffer(Adapter, msg);
		return -1;
	}
}
#endif


